/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
//package MuleGame;
package MuleGUI;
import java.awt.*;
import java.beans.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Random;

import javax.swing.*;
import javax.swing.event.*;
import javax.swing.text.html.StyleSheet;

import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionAdapter;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;

import javax.swing.GroupLayout.Alignment;
import javax.swing.LayoutStyle.ComponentPlacement;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;

import MuleBackend.Board;
import MuleBackend.GameDriver;
import MuleBackend.InfoPanel;
import MuleBackend.Inventory;
import MuleBackend.Land;
import MuleBackend.Player;
import MuleBackend.StorePanel;

/**
 * The BoardGUI class represents the board for the entire game
 * @author Jackson
 */
public class BoardGUI extends javax.swing.JFrame {
	ImageIcon image;
	JLabel[][] labels;
	JLabel[][] factory;
	JLabel randomLabel;
	ArrayList<InfoPanel> infoPanels;
	StorePanel storePanel;
	private HashMap<JLabel,Land> map;
	transient static JProgressBar timeBar;
	JMenuBar menuBar;
	JMenu newGameMenu;
 	JMenu saveMenu;
 	JMenu loadMenu;
 	JMenu joinMenu;
 	JMenu exitMenu;
	JMenuItem newGameMenuStartItem;
 	JMenuItem saveMenuSaveItem;
 	JMenuItem loadMenuLoadItem;
	int x,y,speed,muleX,muleY;
 	ArrayList<Player> players;
 	JPanel mainPanel;
 	static boolean startPlayer = false;
	
	private ImageIcon foodFactory = new ImageIcon("src/ShittyPackage/foodFactory.png");
	private ImageIcon energyFactory = new ImageIcon("src/ShittyPackage/energyFactory.png");
	private ImageIcon smithoreFactory = new ImageIcon("src/ShittyPackage/smithoreFactory.png");
	private ImageIcon crystiteFactory = new ImageIcon("src/ShittyPackage/crystiteFactory.png");
	
    /**
     * Creates new form Board
     */
    public BoardGUI() {
		labels = new JLabel[5][9];
		factory = new JLabel[5][9];
		infoPanels = new ArrayList<InfoPanel>();
		storePanel = null;
		x = 100;
		y = 100;
		speed = 10;
		muleX = x;
		muleY = y;
		
		buildGUI();
		map=new HashMap<JLabel,Land>();
    }	//end of constructor
    
    /**
     * this method create the main panel and
     * the menu of the board
     */
    private void buildGUI(){
    	setTitle("Mule Game (boardGUI)");
    	setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    	getContentPane().setPreferredSize(new Dimension(925, 600));
    	pack();
		setResizable(false);
    	setLocationRelativeTo(null);

		setMainPanel(new JPanel());
		getMainPanel().setBorder(new EmptyBorder(5,5,5,5));
		setContentPane(getMainPanel());
		getMainPanel().setLayout(null);
		
		menuBar = new JMenuBar();
    	
		newGameMenu = new JMenu("New Game");
        saveMenu = new JMenu("Save");
        loadMenu = new JMenu("Load");
        joinMenu = new JMenu("Join Game");
        exitMenu = new JMenu("Exit");
        
        menuBar.add(newGameMenu);
        menuBar.add(saveMenu);
        menuBar.add(loadMenu);
        menuBar.add(joinMenu);
        menuBar.add(exitMenu);
        
        randomLabel=new JLabel("");
        randomLabel.setBounds(0,475,900,25);
        randomLabel.setHorizontalTextPosition(JLabel.CENTER);
        randomLabel.setForeground(Color.WHITE);
        randomLabel.setVisible(false);
        getContentPane().add(randomLabel);
        
        newGameMenuStartItem = new JMenuItem("Start");
        newGameMenuStartItem.addActionListener(new StartButtonListener());
        saveMenuSaveItem = new JMenuItem("Save Game");
        saveMenuSaveItem.addActionListener(new SaveButtonListener());
        loadMenuLoadItem = new JMenuItem("Load Game");
        loadMenuLoadItem.addActionListener(new LoadButtonListener());
        
        newGameMenu.add(newGameMenuStartItem);
        saveMenu.add(saveMenuSaveItem);
        loadMenu.add(loadMenuLoadItem);
		setJMenuBar(menuBar);
		
		addKeyListener(new PlayerControl());
		setFocusable(true);
		setFocusTraversalKeysEnabled(false);
    }

    /**
     * private helper method to add the information panels of all the players to the board GUI 
     */
    public void addInfoPanels(){
   		for (int i=0; i<4 ;i++){
   			if (i<players.size()){
   				InfoPanel thepanel = new InfoPanel(players.get(i));
   				infoPanels.add(thepanel);
   				getContentPane().add(thepanel);
   				thepanel.setBounds(185*i,500,185,100);
   			}else{
   				InfoPanel thepanel = new InfoPanel(i+1);
   				infoPanels.add(thepanel);
   				getContentPane().add(thepanel);
   				thepanel.setBounds(185*i,500,185,100);
   			}
   		}
   		storePanel = new StorePanel();
   		getContentPane().add(storePanel);
   		storePanel.setBounds(185*4,500,185,100);
    }
    
    
    /**
     * this method create progress bar inside board
     * this method is called from addMap method
     */
	public void addProgressBar(){
        timeBar = new javax.swing.JProgressBar();
        timeBar.setLocation(900, 0);
        timeBar.setSize(25, 500);
        timeBar.setStringPainted(true);
        timeBar.setOrientation(SwingConstants.VERTICAL);
        timeBar.setBackground(Color.BLACK);
        getContentPane().add(timeBar);
	}
    
    /**
     * creates a GUI representation of the MULE map
     */
    public void addMap(){
		players = GameDriver.game.getPlayerList();
		Land[][] landsArray = GameDriver.game.getLandsArray();
		
		for (int i = 0; i < labels.length;i++){
			for (int j = 0; j < labels[i].length;j++){
				image = landsArray[i][j].getImage();
				labels[i][j] = new JLabel(image);
				factory[i][j] = new JLabel();
				labels[i][j].setBounds(100*j,100*i, 100, 100);
				factory[i][j].setBounds(100*j,100*i, 100, 100);
				getContentPane().add(factory[i][j]);
				getContentPane().add(labels[i][j]);
				map.put(labels[i][j], landsArray[i][j]);
			}
		}
		addProgressBar();
		addInfoPanels();
		addLandListener();
		getContentPane().setPreferredSize(new Dimension(925, 600));
		pack();
    }
    
    /**
     * helper method to add the town listener
     */
    public void addTownListener(){
    	labels[2][4].addMouseListener(new TownListener());
    }
    
    /**
     * adds listeners to the board
     * execute this method before addTownListener.
     */
    public void addLandListener(){		
    	for (int i = 0; i < labels.length; i++){
    		for(int j = 0; j < labels[i].length; j++){
    				labels[i][j].addMouseListener(new AddLandListener());
    				labels[i][j].addMouseListener(new AddFactoryListener());
    			}
    		}
    	MouseListener[] mousey = labels[2][4].getMouseListeners();
    	labels[2][4].removeMouseListener(mousey[0]);
    	labels[2][4].removeMouseListener(mousey[1]);
    	addTownListener();
    }
    
	/**
	 * getter method to get the progress bar
	 * @return the timebar
	 */
	public static JProgressBar getJProgressBar(){
		return timeBar;
	}
    
	/**
	 * updates all the information panels on the board
	 */
	public void updateInfoPanels(){
		for (int i=0; i<players.size(); i++){
			InfoPanel panel = infoPanels.get(i);
			panel.updatePanel();
		}
		storePanel.updatePanel();
	}    
    
    /**
     * this method set the start location for players
     * @param x the coordinate of x-axis
     * @param y the coordinate of y-axis
     */
    public void startPlayer(int x, int y){
    	this.x = x;
		this.y = y;
		muleX = x;
		muleY = y;
		setFocusable(true);
		startPlayer = true;
		repaint();
    }
    
    
    
    /**
     * this remove the player from 
     */
    public void stopPlayer(){
    	setFocusable(false);
    	startPlayer = false;
    	repaint();
    }
    
    
    
    
    /**
     * this method create the player character 
     */
    public void paint(Graphics g){
		super.paint(g);

		if (startPlayer){
			ImageIcon character = GameDriver.game.getCurrentPlayer().getRace();
			g.drawImage(character.getImage(),x, y, 50, 50,null);
			if (GameDriver.game.getCurrentPlayer().getMuleImage()!=null)
				g.drawImage(GameDriver.game.getCurrentPlayer().getMuleImage().getImage(),muleX,muleY,50, 50,null);
		}
		
	}
    
    /**
     * method that switches to factory listeners
     */
    public void switchToFactoryListeners(){
    	for(int i=0;i<labels.length;i++){
			for(int j=0;j<labels[i].length;j++){
				try{
					((AddLandListener)labels[i][j].getMouseListeners()[0]).enabled=false;
					((AddFactoryListener)labels[i][j].getMouseListeners()[1]).enabled=true;
				}catch(Exception e){}
			}
		}
    	((TownListener)labels[2][4].getMouseListeners()[0]).setEnabled(true);
    }
    
    /**
     * method that switches to the land listeners
     */
    public void switchToLandListeners(){
    	for(int i=0;i<labels.length;i++){
			for(int j=0;j<labels[i].length;j++){
				try{
					((AddLandListener)labels[i][j].getMouseListeners()[0]).enabled=true;
					((AddFactoryListener)labels[i][j].getMouseListeners()[1]).enabled=false;
				}catch(Exception e){}
			}
		}
    	((TownListener)labels[2][4].getMouseListeners()[0]).setEnabled(false);
    }
    /*
     * Methods for Land Auction and Land Sale
     */
    
    /**
     * Picks a land for auction
     * @param board the game board
     * @return returns a random free piece of land
     */
    private Land pickLand(Board board){
    	ArrayList<Land> freeLands = board.getFreeLands();
    	if(freeLands.size()==0)
    		return null;
    	Random random = new Random();
    	int i = random.nextInt(freeLands.size());
    	return freeLands.get(i);
    }
    
    /**
     * gets the auction land and displays it
     * 
     * @return  free land in board, or null if there is no free piece of land
     */
    public Land startLandSale(){
    	Board board = GameDriver.game.getBoard();
    	Land freeLand = pickLand(board);
    	int index = board.findLandIndex(freeLand);
    	if(index==-1)
    		return null;
    	System.out.println("LAND SALE INDEX = " + index/9 + " " + index%9);
    	for(int k=0;k<3;k++){
    		//System.out.println("blink");
    		labels[index/9][index%9].setBorder(new LineBorder(Color.BLACK, 2));
    	}
    	//labels[index/9][index%9].setBorder(null);
    	return freeLand;
    }
    /**
     * colorLand colors a piece of land with the specified color
     * @param row row index of land
     * @param col column index of land
     * @param colorString color to be painted, null if you want color to be removed
     */
    public void colorLand(int row, int col, Color landColor){
    	if(landColor==null){
    		labels[row][col].setBorder(null);
    		return;
    	}
    	labels[row][col].setBorder(new LineBorder(landColor,2));
    }
    
    /**
     * uses the above colorLand to color a piece of land by taking in different parameters
     * @param land land to be colored
     * @param player the player who owns the land
     */
    
    public void colorLand(Land land, Player player){
    	int row = land.getRow()+1;
    	int col = land.getCol()+1;
    	System.out.println("Row = " + row + " Col = " + col);
    	Color color = null;
    	if(player==null)
    		color = null;
    	else
    		color = player.getColor();
    	colorLand(row,col,color);
    }
    
    /*
     * End of methods for land auction and land sale
     */
    
	/**
	 * These methods are for use primarily with the PubListener in StoreGUI.
	 * 
	 * The getTurnPercentRemaining() method accesses the progress bar on the right hand
	 * side of the board and returns the percentage of the bar remaining at the time of 
	 * the method's call.
	 * 
	 * The endTurn() method is called at the end of the PubListener as a terminating
	 *function for the current player's turn.
	 *
	 *@author Phil
	 *
	 */
    public double getTurnPercentRemaining()
	{
		return getJProgressBar().getPercentComplete();
	}
    
    
    /**
     * method to end the turn
     */
	public void endTurn()
	{
		
		//this "disables" the board GUI by disabling the actionlisteners. the other methods I tried were buggy/inconsistent, but if need be
		// I could modify the code of Board, Town, and Stages to make this logic cleaner. I read up on GlassPanes, which seemed promising,
		//but I think they only cover the frame, so the panels would still receive input.
		for(int i=0;i<labels.length;i++){
			for(int j=0;j<labels[i].length;j++){
				try{
					((AddLandListener)labels[i][j].getMouseListeners()[0]).enabled=false;
					((AddFactoryListener)labels[i][j].getMouseListeners()[1]).enabled=false;
				}catch(Exception e){
					((TownListener)labels[i][j].getMouseListeners()[0]).enabled=false;
				}
			}
		}
	}

	/**
	 * getter method to get the board gui
	 */
	public BoardGUI getBoardGUI() {
		return this;
	}
    
    
	    
	/**
	 * getter method to get the main panel
	 * @return mainPanel
	 */
	public JPanel getMainPanel() {
		return mainPanel;
	}

	/**
	 * setter method to set the main panel
	 * @param mainPanel mainpanel to set to
	 */
	public void setMainPanel(JPanel mainPanel) {
		this.mainPanel = mainPanel;
	}


	/**
	 * prints a message to the screen
	 * @param message the message to show
	 */
	public void showRandomLabel(String message){
		randomLabel.setText(message);
		randomLabel.setVisible(true);
	}
	
	/**
	 * hide the label for the random event message
	 */
	public void hideRandomLabel(){
		randomLabel.setVisible(false);
	}


	/**
	 * private inner class to add an action listener to the town
	 * @author Jackson
	 *
	 */
	private class TownListener extends MouseAdapter {
	
		boolean enabled;
		
		/**
		 * constructor for the town listener
		 */
	   	public TownListener() {
	   		enabled=false;
	   	}
	   	
	   	/**
	   	 * setter method to set the enabled value
	   	 * @param enabled whether or not the it is enabled or not
	   	 */
	   	public void setEnabled(boolean enabled){
	   		this.enabled=enabled;
	   	}
	   	
	   	/**
	   	 * action even that happens when the town is clicked
	   	 * brings up the town gui
	   	 */
	   	public void mouseClicked(MouseEvent e) {
	   		if(!enabled)return;
	   		if (GameDriver.game.getCurrentStage().equals("turns")){
	   			GameDriver.game.showTownGUI();
	   		}
	   	}
	} //end of Town Listener class
	    
	
	/**
	 * factory listener class that adds the factory listener
	 * to a piece of land
	 * @author Andrew
	 *
	 */
	public class AddFactoryListener extends MouseAdapter{
		boolean enabled;
		
		/**
		 * constructor for the addfactorylistener class
		 */
		public AddFactoryListener(){
			enabled=false;
		}
		
		/**
		 * setter method to set the value of enabled
		 * @param enabled whether or not it is enabled
		 */
		public void setEnabled(boolean enabled){
			this.enabled=enabled;
		}
		
		/**
		 * action event that occurs when the mouse is clicked
		 */
		public void mouseClicked(MouseEvent e){
			if(!enabled)return;
			JLabel label=(JLabel)e.getSource();
			Land land=map.get(label);
			Player activePlayer = GameDriver.game.getActivePlayer();
			
			if(land.getOwner() == activePlayer){
				
				if(activePlayer.getMule()>Inventory.PLAIN_MULE){
					System.out.println("Player " +activePlayer+ " has placed a mule of type " + activePlayer.getMule());
					land.setFactory(activePlayer.getMule());
					activePlayer.setMule(Inventory.NO_MULE);
					
				}else{
					JOptionPane.showMessageDialog(new JLabel(),"Outfit a MULE first!");
				}
			}else{
				JOptionPane.showMessageDialog(new JLabel(),"You don't own this land, so your MULE was lost. Try again.");
				activePlayer.setMule(Inventory.NO_MULE);
			}
			
		}
	}	//end of add factoy listener class


	/**
	 * land listener class that determines what to do
	 * when a land is clicked
	 * @author Jackson
	 *
	 */
	public class AddLandListener extends MouseAdapter {
		
		boolean enabled;
	   	
		/**
		 * constructor for the addlandlistener class
		 */
	   	public AddLandListener() {
	   		enabled=true;
	   	}
	   	
	   	/**
	   	 * action event that happens when a land is clicked
	   	 */
	   	public void mouseClicked(MouseEvent event) {
	   		freeLandLogic(event);	//logic for assigning lands to players during land selection phase
	   	}
	   	
	   	
	   	
	   	/**
	   	 * private helper method that assigns free land
	   	 * @param e the mouse event of clicking a land
	   	 */
	   	private void freeLandLogic(MouseEvent e){
	   		if(!enabled)return;
	   		
	   		Land[][] lands = GameDriver.game.getLandsArray();
	   		int theRoundNumber = GameDriver.game.getRoundNumber();
	   		Player activePlayer = GameDriver.game.getActivePlayer();
	   		
	   		if (activePlayer != null && freeLandStage(activePlayer.getPlayerID())) {
	   			
	   	   		
			   		JLabel label = (JLabel)e.getSource();
					Color color = activePlayer.getColor();
		   		
		   		for (int row = 0; row < labels.length; row++) {
		   			for (int column = 0; column < labels[row].length; column++) {
		   				if (label == labels[row][column]) {
		   					if (notOwned(row, column)) {
		   						if (theRoundNumber < 3) {
			   						label.setBorder(new LineBorder(color, 2));
			   						activePlayer.addLand(lands[row][column]);
			   						GameDriver.game.setCurrentPlayer(null);
		   						} else {
				   					if (activePlayer.getMoney() >= lands[row][column].getPrice()) {
			   							label.setBorder(new LineBorder(color, 2));
				   						activePlayer.addLand(lands[row][column]);
				   						activePlayer.deductMoney(lands[row][column].getPrice());
				   						GameDriver.game.setCurrentPlayer(null);
				   					}
				   				}
		   					}	//end of if (not owned) statement
		   				}
		   			}
		   		}	//end of double for loop
	   		}	//end of if statement
	   	}	//end of freeLandLogic
	   	
	   	/**
	   	 * helper method to determine if it is
	   	 * the free land stage or not
	   	 * @param currentPlayerID current player
	   	 * @return true if it is the free land stage and there is a player
	   	 */
	   	private boolean freeLandStage(int currentPlayerID){
	   		if (currentPlayerID != 0 && GameDriver.game.getCurrentStage().equals("freeLand")){
	   			return true;
	   		}
	   		else {
	   			return false;
	   		}
	   	}
	   	
	   	/**
	   	 * helper method to determine if the land
	   	 * is owned or not
	   	 * @param row row of the land
	   	 * @param column column of the land
	   	 * @return
	   	 */
	   	private boolean notOwned(int row, int column){
	   		Player currentPlayer = GameDriver.game.getActivePlayer();
	   		Land[][] lands = GameDriver.game.getLandsArray();
	   		if (lands[row][column].getOwner() == null) {
	   			lands[row][column].setOwner(currentPlayer);
	   			return true;
	   		}
	   		return false;
	   	}
	} //end of LandListener class
	
	
	/**
	 * inner class for the start button listener
	 * that starts the game
	 * @author Jackson
	 *
	 */
	public class StartButtonListener implements ActionListener {
	    	
		/**
		 * constructor for the start button listener
		 */
	    public StartButtonListener() {
	    	//empty
	    }
	    
	    /**
	     * action event that happens when the start button i clicked
	     */
	    public void actionPerformed(ActionEvent e) {
	    	new StartGUI().setVisible(true);
	    }
	} //end of StartButtonListener class

	
	public class SaveButtonListener implements ActionListener {
		public SaveButtonListener() {
			//empty
		}
		
		/**
		 * action to perform when the player clicks the 
		 * save game button
		 */
		public void actionPerformed(ActionEvent e) {
			GameDriver.game.saveGame();
		}
	}
	
	/**
	 * action listener for the load game button
	 * allows you to load the game
	 * @author Jackson
	 *
	 */
	public class LoadButtonListener implements ActionListener {
		public LoadButtonListener() {
			//empty
		}
		
		/**
		 * action to perform when the load game button has
		 * been pressed
		 */
		public void actionPerformed(ActionEvent e) {
			GameDriver.loadGame();
		}
	}


	/**
	 * the class allow the player character to move using keyboard
	 * @author Spyro
	 *
	 */
	private class PlayerControl implements KeyListener{
		
		/**
		 * controls player movement
		 */
		public void keyPressed(KeyEvent e){
			
			char ch = e.getKeyChar();
			
			if (ch == 'a' || e.getKeyCode() == KeyEvent.VK_LEFT)
				if (x>5){
					x = x - speed;
					muleX = x+50;
					muleY = y;
				}
			if (ch == 'w' || e.getKeyCode() == KeyEvent.VK_UP)
				if (y>40){
					y = y - speed;
					muleY = y+50;
					muleX = x;
				}
			if (ch == 'd' || e.getKeyCode() == KeyEvent.VK_RIGHT)
				if (x<850){
					x = x + speed;
					muleX = x-50;
					muleY = y;
				}
			if (ch == 's' || e.getKeyCode() == KeyEvent.VK_DOWN)
				if (y<490){
					y = y + speed;
					muleY = y-50;
					muleX = x;
				}
			if (ch == ' '){
				doStuff();
			}
			if (x>=370 && x<=390 && y>=200 && y<=300){
				GameDriver.game.showTownGUI(10,305);
				stopPlayer();
			}
			if (x>=460 && x<=480 && y>=200 && y<=300){
				GameDriver.game.showTownGUI(800,305);
				stopPlayer();
			}
			if (x>=400 && x<=480 && y>=200 && y<=220){
				GameDriver.game.showTownGUI(405,10);
				stopPlayer();
			}
			if (x>=400 && x<=480 && y>=300 && y<=320){
				GameDriver.game.showTownGUI(405,600);
				stopPlayer();
			}
			
			repaint();
		}
	
		@Override
		public void keyTyped(KeyEvent e) {
			// TODO Auto-generated method stub
			
		}
	
		@Override
		public void keyReleased(KeyEvent e) {
		}
	
	}	//end of player contorll clss
	/**
	 * this method performed tasks when the space is pressed
	 * such as setting the mule to a land if the player owns
	 * the land or makes the mule run away if they dont
	 * own the land
	 */
	public void doStuff(){
		Player currentPlayer = GameDriver.game.getCurrentPlayer();
		Land[][] landsArray = GameDriver.game.getLandsArray();
		for (int j=1; j<=5; j++){
			if (y>=(100*(j-1)) && y<=(100*j)){
				for (int i=1; i<=9; i++){
					if (x>=(100*(i-1)) && x<=(100*i)){
						System.out.println(j+","+i);
						Player currentPlay = landsArray[j-1][i-1].getOwner();
						if (currentPlay == (currentPlayer)){
							ImageIcon images = createFactory(currentPlayer.getMule());
							landsArray[j-1][i-1].setFactory(currentPlayer.getMule()-1);
							if (images != null){
								factory[j-1][i-1].setIcon(images);
								currentPlayer.setMule(0);
							} else {
								currentPlayer.setMule(0);
								JOptionPane.showMessageDialog(new JLabel(),"MULE has been lost!");
							}
						} else {
							currentPlayer.setMule(0);
							JOptionPane.showMessageDialog(new JLabel(),"MULE has been lost!");
						}
					}
				}
			}
		}
		
	}
	
	/**
	 * this is the helper method for creating factory
	 * @param mule
	 * @return
	 */
	private ImageIcon createFactory(int mule){
		if (mule == 2)return foodFactory;
		if (mule == 3)return energyFactory;
		if (mule == 4)return smithoreFactory;
		if (mule == 5)return crystiteFactory;
		return null;
	}
} //end of BoardGUI class